﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Streambolics.App
{
    /// <summary>
    ///     The history of correction attempts applied to a module.
    /// </summary>

    public class ModuleRecoveryHistory
    {
        private Dictionary<ModuleRecoveryStrategy, ModuleRecoveryAttempt> _Attempts = new Dictionary<ModuleRecoveryStrategy, ModuleRecoveryAttempt> ();
        private ComputingModule _Module;
        private DateTime _FailureDetection;

        internal ModuleRecoveryHistory (ComputingModule aModule)
        {
            _Module = aModule;
            _FailureDetection = DateTime.Now;
        }

        public DateTime FailureDetection
        {
            get
            {
                return _FailureDetection;
            }
        }

        /// <summary>
        ///     Whether the history can be forgotten.
        /// </summary>
        /// <returns>
        ///     True if the correction attempts seem successful, false otherwise.
        /// </returns>

        internal bool MayForget ()
        {
            List<ModuleRecoveryStrategy> Corrected = new List<ModuleRecoveryStrategy> ();
            foreach (var entry in _Attempts)
            {
                if (entry.Value.MayForget ())
                {
                    Corrected.Add (entry.Key);
                }
            }
            foreach (var k in Corrected)
            {
                _Attempts.Remove (k);
            }
            return _Attempts.Count == 0;
        }

        /// <summary>
        ///     Attempts the recovery of the module
        /// </summary>
        /// <param name="aStrategy">
        ///     The strategy to attempt.
        /// </param>
        /// <returns>
        ///     True if the strategy was attempted, false otherwise.
        /// </returns>

        internal bool AttemptRecovery (ModuleRecoveryStrategy aStrategy)
        {
            if (!aStrategy.AppliesTo (_Module))
            {
                return false;
            }

            if (!_Attempts.ContainsKey (aStrategy))
            {
                if (aStrategy.FirstAttempt (_Module, this))
                {
                    ModuleRecoveryAttempt a = new ModuleRecoveryAttempt (aStrategy);
                    _Attempts.Add (aStrategy, a);
                    return true;
                }
            }
            else
            {
                ModuleRecoveryAttempt a = _Attempts[aStrategy];
                if (aStrategy.NextAttempt (_Module, a))
                {
                    a.RecordNextAttempt ();
                    return true;
                }
            }
            return false;
        }
    }
}
